package statistics

import (
	"context"
	"encoding/json"
	"sale-admin/config/mysql"
	"sale-admin/internal/app/grpc/client"
	"sale-admin/internal/app/grpc/protoc/devicec"
	"sale-admin/internal/app/grpc/protoc/system_admin"
	"sale-admin/internal/app/web/schema"
	"sale-admin/internal/app/web/service/common"
	"sale-admin/internal/app/web/service/robot"
	"sale-admin/internal/dal"
	"sale-admin/internal/dao"
	"sale-admin/internal/define"
	"sort"
	"strings"
	"time"

	"sale-admin/internal/models"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/logx"
	"github.com/golang-module/carbon"
	"github.com/samber/lo"
	"gorm.io/gorm"
)

type OrderStatisticService struct{}

// StatGoodsInfo 获取当前机器的商品信息
func (o OrderStatisticService) StatGoodsInfo(
	ctx context.Context,
	db *gorm.DB,
	salesID string,
) (
	data []schema.GoodDataType,
	err error,
) {
	start_time := carbon.Now().ToDateString() + " 00:00:00"
	end_time := carbon.Now().ToDateString() + " 23:59:59"
	// 获取机器点击数
	res, err := robot.RobotClick{}.GetRobotGoodsClick(ctx, db, salesID, start_time, end_time)
	var newClickData = make(map[string]robot.GoodsClickType)
	if len(res) != 0 {
		for _, v := range res {
			newClickData[v.GoodsID] = v
		}
	}
	//1.查询 【当天 】所有状态下的商品进行分组统计
	tx := db.Model(&models.MaOrder{})
	if salesID != "" {
		tx.Where("sales_id = ?", salesID)
	}
	tx.Where("add_time between ? and ?", start_time, end_time) //实时数据是当天截止时间
	var goodsData []schema.GoodDataType
	tx.Select(
		"count_data",
		"json_extract_c(count_data, \"$.GoodsID\") AS my_goods_id",
		"robot_name",
		"sales_id",
		"order_id",
		"payment_amount",
		"order_status",
		"(SELECT 0) AS pay_num",
		"(SELECT 0) AS repeat_pay_num",
	).Find(&goodsData)

	// 获取商品名称和商品ID
	for k, v := range goodsData {
		// json_decode
		var countDataSlice []schema.OrderGoodsDetailOld
		json.Unmarshal([]byte(v.CountData), &countDataSlice)
		if len(countDataSlice) != 0 {
			v.GoodsName = countDataSlice[0].GoodsName
			v.GoodsID = countDataSlice[0].GoodsID
		}
		goodsData[k] = v
	}
	// 商品点击数
	var all_goods = make(map[string][]schema.GoodDataType)
	var all_goods_one = make(map[string]schema.GoodDataType)
	for _, v := range goodsData {
		// all_goods[v.MyGoodsId] = append(all_goods[v.MyGoodsId], v)
		all_goods[v.MyGoodsId] = append(all_goods[v.MyGoodsId], v)
		if newClickData[v.MyGoodsId].ClickNum > 0 {
			v.ClickNum = newClickData[v.MyGoodsId].ClickNum
		} else {
			v.ClickNum = 0
		}
		all_goods_one[v.MyGoodsId] = v
	}
	// 根据不同的订单状态进行组装
	var all = make(map[string]map[int][]schema.GoodDataType) // 序列ID-》 订单状态-》订单商品数组
	for k, v := range all_goods {
		orderStatusMap := make(map[int][]schema.GoodDataType)
		for _, val := range v {
			// fmt.Println("我的打印", val)
			// fmt.Println("k", k)
			// fmt.Println("key", key)
			orderStatusMap[val.OrderStatus] = append(orderStatusMap[val.OrderStatus], val)
		}
		all[k] = orderStatusMap
	}

	// 获取GMV和count
	new := make(map[string]map[int]schema.GoodDataType)
	for k, v := range all {
		newMap := make(map[int]schema.GoodDataType)
		for key, val := range v {
			// 计算GMV
			var mygmv float32 = 0
			for _, n := range val {
				mygmv += n.PaymentAmount
			}
			val[0].Count = len(val)
			val[0].Gmv = mygmv
			newMap[key] = val[0]
			new[k] = newMap
		}
	}

	// 获取new，并返回
	var count int = 0
	var mynew = []schema.GoodDataType{}
	for k, v := range new {
		//分需求统计 （gmv 成交额 ..）
		mynew = append(mynew, all_goods_one[k]) // 把关联数组变成索引数组
		mynew[count].Gmv = 0                    //gmv
		mynew[count].MyPaymentAmount = 0        //成交额
		mynew[count].MyRefundOrderAmount = 0    //退款额
		mynew[count].MyStartOrderCount = 0      //创建订单
		mynew[count].MySuccessOrderCount = 0    //支付订单
		mynew[count].MyNotPayOrderCount = 0     //未支付支付订单
		mynew[count].MyRefundOrderCount = 0     //退款订单
		mynew[count].OrderPercent = ""          //退款订单
		mynew[count].Count = 0

		for key, val := range v {
			mynew[count].Gmv += val.Gmv //总的
			mynew[count].Count += val.Count
			mynew[count].MyStartOrderCount += val.Count
			if key == 6 {
				mynew[count].MyRefundOrderAmount += val.Gmv
			}
			if key == 4 {
				mynew[count].MySuccessOrderCount += val.Count
				mynew[count].MyPaymentAmount += val.Gmv
			}
			if key == 3 || key == 1 {
				mynew[count].MyNotPayOrderCount += val.Count
			}
			if key == 6 {
				mynew[count].MyRefundOrderCount += val.Count
			}
			if mynew[count].MyStartOrderCount > 0 && mynew[count].MySuccessOrderCount > 0 {
				mynew[count].OrderPercent = "10%" // string(100*(item.MySuccessOrderCount/item.GoodsOrderMyStartOrderCount)) + "%" //订单转化率
			}
		}
		count++
	}
	// 返回最后结果
	return mynew, err
}

// 获取机器的实时商品数据
func (o OrderStatisticService) GetGoodsInfo(ctx context.Context, db *gorm.DB, res []schema.OrderStatData) (data []schema.OrderStatData, err error) {

	for k, v := range res {
		// 根据SalesID获取每台机器商品信息
		v.GoodsInfo, _ = o.StatGoodsInfo(ctx, db, v.SalesID)
		//  添加了goodsInfo数据后，重新赋值
		res[k] = v
	}
	return res, err
}

// 获取所有带有商户的机器 （face_count>0）
func (o OrderStatisticService) GetAllRobotByMerchantID(ctx context.Context, db *gorm.DB, page, limit int,
	start_time, end_time string, allMerchantIDArr []string, RobotName string,
) (
	RobotList []models.MaRobot, totalCount int64, err error,
) {
	tx := db.Model(&models.MaRobot{}).
		Where("robot_type in (5,11) and deleted = 0")
	// 机器名称
	if RobotName != "" {
		tx.Where("robot_name in (?)", strings.Split(RobotName, ",")) // 获取指定商户下的机器
	}
	// 商户列表
	if len(allMerchantIDArr) != 0 {
		tx.Where("merchant_id in (?)", allMerchantIDArr) // 获取指定商户下的机器
	} else {
		tx.Where("merchant_id <> ?", 1) // 获取已经分配商户的机器
	}

	if page != 0 && limit != 0 {
		tx.Count(&totalCount)
		helper.Gorm{}.Paginate(tx, page, limit).Order("robot_name asc").Find(&RobotList)
	} else {
		totalCount = tx.Order("robot_name asc").Find(&RobotList).RowsAffected
	}
	return
}

// 获取所有带有商户的机器 （face_count>0）
func (o OrderStatisticService) GetAllMerchantByMerchantID(
	ctx context.Context, db *gorm.DB,
	page, limit int,
	start_time, end_time, merchantID string,
) (
	MerchantList []models.MaMerchantConfig,
	totalCount int64,
	err error,
) {
	// 获取可用的商户

	tx := db.Table(models.MaMerchantConfig{}.TableName() + " as m").
		Joins(" left join " + models.MaRobot{}.TableName() + " as r on r.merchant_id = m.id").
		Joins(" left join " + models.MaAIServiceFaceCount{}.TableName() + " as a on a.sales_id = r.sales_id").
		Group("r.merchant_id")
	if page != 0 && limit != 0 {
		if merchantID != "1" {
			tx.Where("r.merchant_id = ?", merchantID) // 仅获取当前登录的商户
		} else {
			tx.Where("r.merchant_id <> ?", 1) // 获取所有的商户
		}
		tx.Where("a.face_count > ?", 0)
		// tx.Where("a.start_time between ? and ?", start_time, end_time)
		tx.Count(&totalCount)
		helper.Gorm{}.Paginate(tx, page, limit).Order("r.robot_name asc").Find(&MerchantList)
	} else {
		return nil, 0, nil
	}

	return
}

type MyAiFaceCountData struct {
	RobotName  string  `json:"robot_name"`
	FaceCount  float64 `json:"face_count"`
	FaceCount0 float64 `json:"face_count0"`
	FaceCount1 float64 `json:"face_count1"`
	FaceCount2 float64 `json:"face_count2"`
	FaceCount3 float64 `json:"face_count3"`
	ClickNum   int     `json:"click_num"`
}

type MyClickData struct {
	RobotName string `json:"robot_name"`
	ClickNum  int    `json:"click_num"`
}

// 统计今日销售额 【实时数据】
func (o OrderStatisticService) GetTodayOrder(ctx context.Context, db *gorm.DB, merchantID string, robotIds string) (result float64, err error) {
	// 起始时间
	start_time := carbon.Now().StartOfDay().ToDateTimeString()
	end_time := carbon.Now().ToDateTimeString()
	tx := db.Model(&models.MaOrder{})
	if merchantID != "1" && merchantID != "" {
		tx.Where("merchant_id = ?", merchantID)
	}
	if robotIds != "" {
		// 分隔拼接
		a := strings.Split(robotIds, ",")
		tx.Where("robot_name in (?)", a)
	}

	var todayAmountStruct struct {
		TodayAmount float64 `gorm:"column:today_amount"`
	}
	field := "sum(payment_amount) as today_amount"
	tx.Where("order_status = ?", 4)
	tx.Where("add_time between ? and ?", start_time, end_time).
		Order("add_time desc").
		Select(field).
		Take(&todayAmountStruct)
	return todayAmountStruct.TodayAmount, nil
}

// 查询日均销售额 【实时数据】
func (o OrderStatisticService) GetDayAvgOrder(ctx context.Context, db *gorm.DB, merchantID string, robotIds string) (
	result float32, err error,
) {
	// 起始时间,查询近30天的数据d
	end_time := carbon.Now().StartOfDay().ToDateTimeString()
	start_time := carbon.CreateFromTimestamp(carbon.Now().Timestamp() - 30*24*3600).ToDateTimeString()
	tx := db.Model(&models.MaOrder{})
	if merchantID != "1" {
		tx.Where("merchant_id = ?", merchantID)
	}
	if robotIds != "" {
		// 分隔拼接
		a := strings.Split(robotIds, ",")
		tx.Where("robot_name in (?)", a)
	}

	var dayAmountStruct struct {
		DayAmount float64 `gorm:"column:day_amount"`
	}

	tx.Where("order_status = ?", 4).
		Where("add_time between ? and ?", start_time, end_time).
		Order("add_time desc").
		Select("sum(payment_amount) as day_amount").
		Take(&dayAmountStruct)
	if dayAmountStruct.DayAmount == 0 {
		return 0, err
	} else {
		return float32(dayAmountStruct.DayAmount) / 30, err
	}
}

// 查询今日和昨日销售额, 上周今日 （-7天）
func (o OrderStatisticService) GetDayOrder(ctx context.Context, db *gorm.DB, merchantID, robotIds string) (result map[string]float64, err error) {
	result = make(map[string]float64)
	// 今日的起始时间
	start_time := carbon.Now().StartOfDay().ToDateTimeString()
	end_time := carbon.Now().ToDateTimeString()
	tx := db.Model(&models.MaOrder{})
	tx1 := db.Model(&models.MaOrder{})
	tx2 := db.Model(&models.MaOrder{})
	if merchantID != "1" && merchantID != "" {
		tx.Where("merchant_id = ?", merchantID)
		tx1.Where("merchant_id = ?", merchantID)
		tx2.Where("merchant_id = ?", merchantID)
	}

	if robotIds != "" {
		// 分隔拼接
		a := strings.Split(robotIds, ",")
		tx.Where("robot_name in (?)", a)
		tx1.Where("robot_name in (?)", a)
		tx2.Where("robot_name in (?)", a)
	}
	//1、 查询今日的实付金额
	var todayAmountStruct struct {
		TodayAmount float64 `gorm:"column:today_amount"`
	}
	tx.Where("order_status = ?", 4).Where("add_time between ? and ?", start_time, end_time).
		Order("add_time desc").
		Select("sum(payment_amount) as today_amount").
		Take(&todayAmountStruct)

	result["today"] = todayAmountStruct.TodayAmount

	//2、 查询上周今日的实付金额（减7天）
	var WeekPreDayStruct struct {
		WeekDayAmount float64 `gorm:"column:week_day_amount"`
	}
	week_seven_time := carbon.CreateFromTimestamp(carbon.Now().Timestamp() - 7*24*3600).ToDateString()
	week_seven_time_end := carbon.CreateFromTimestamp(carbon.Now().Timestamp() - 6*24*3600).ToDateString()
	tx1.Where("order_status = ?", 4).
		Where("add_time between ? and ?", week_seven_time, week_seven_time_end).
		Order("add_time desc").
		Select("sum(payment_amount) as week_day_amount").
		Take(&WeekPreDayStruct)
	result["week_pre_day"] = WeekPreDayStruct.WeekDayAmount

	// 3.查询昨天的数据
	var yestodayStruct struct {
		WeekDayAmount float64 `gorm:"column:week_day_amount"`
	}
	start_time = carbon.Yesterday().ToDateString() + " 00:00:00"
	end_time = carbon.Yesterday().ToDateString() + " 23:59:59"
	tx2.Where("order_status = ?", 4).
		Where("add_time between ? and ?", start_time, end_time).
		Order("add_time desc").
		Select("sum(payment_amount) as week_day_amount").
		Take(&yestodayStruct)
	result["yestoday"] = yestodayStruct.WeekDayAmount
	return
}

// getClickOfRobot 获取今日点击数 【实时数据】
func (o OrderStatisticService) getClickOfRobot() (data []MyClickData, err error) {
	start_time := carbon.Now().ToDateString() + " 00:00:00"
	end_time := carbon.Now().ToDateString() + " 23:59:59"
	mysql.NewDB().Model(&models.MaGoodsClick{}).
		Where("start_time between ? and ?", start_time, end_time).
		Group("sales_id").
		Order("sales_id").
		Select(
			"robot_name",
			"sum(click_num) as click_num",
		).
		Find(&data)
	return
}

// 获取异常数据的设备，0曝光0点击
// Type 1曝光 2 点击 3 创单
func (o OrderStatisticService) GetAbnormalDevice(ctx context.Context, db *gorm.DB, merchantID string, Type int,
	areas1 string, areas2 string, startTime, endTime int64, page, limit int,
) (result []string, err error) {
	if Type == 0 {
		Type = 1
	}
	merchantIDList, err := common.Order{}.GetMerchantChildren(ctx, merchantID, []string{})
	if err != nil {
		return
	}
	return dao.NewRobotDailyReport(ctx, db).
		WithTimePeriod(startTime, endTime).
		WithMerchantID(strings.Join(merchantIDList, ",")).
		WithProvinceID(areas1).
		WithCityID(areas2).
		AbnormalDeviceList(Type)
}

// 获取当日的实时数据 -- 开放数据
func (o OrderStatisticService) GetStatListV2Open(ctx context.Context, db *gorm.DB,
	Type int,
	merchantID, merchantName string,
	page, limit int,
	SalesID string, // 总合计需要把这个条件带上
	StartTime, EndTime string,
) (
	myresult interface{},
	totalRobotCount int64,
	totalCountData schema.OrderStatData,
	err error,
) {
	var ResultList = []schema.OrderStatData{}
	var TotalCount schema.OrderStatData
	// 查询今天
	startTime := StartTime
	endTime := EndTime + " 23:59:59"
	var myGroup string
	if Type == 1 {
		myGroup = "o.sales_id" // 机器
	} else if Type == 2 {
		myGroup = "o.merchant_id, o.sales_id" // 商户
	} else if Type == 3 {
		myGroup = "o.areas3, o.sales_id" // 商场
	} else {
		err = errorx.New("类型错误", -1)
		return
	}

	// =============== 先获取分页的商户信息 ============
	var allMerchantIDArr = []string{}  //分页了
	var AllMerchantIDList = []string{} //没分页
	if Type == 2 {                     //商户
		// --- 商户分页 ---
		// MerchantList 返回商户列表集合（分页后返回的数据）
		// totalMerchantCount 商户总数(有效的总数)
		// 必须加上条件》商户必须拥有机器，并且商户下的机器为有效的机器。（机器必须满足：曝光>0 或者 有创单数）
		// GetAllMerchantByMerchantIDV2
		MerchantList, totalMerchantCount, _ := o.GetAllMerchantByMerchantID(ctx, db, page, limit, startTime, endTime, merchantID)
		if totalMerchantCount != 0 && len(MerchantList) != 0 {
			for _, v := range MerchantList {
				allMerchantIDArr = append(allMerchantIDArr, v.ID)
			}
		}
		merchantIDs, err1 := common.Order{}.GetMerchantChildren(ctx, merchantID, []string{merchantID})
		if err1 != nil {
			err = err1
			return
		}
		AllMerchantIDList = merchantIDs
	} else if Type == 1 || Type == 3 { // 机器 || 商场
		merchantIDs, err1 := common.Order{}.GetMerchantChildren(ctx, merchantID, []string{merchantID})
		if err1 != nil {
			err = err1
			return
		}
		allMerchantIDArr = merchantIDs
		AllMerchantIDList = merchantIDs
	}

	// ------------- 机器分页 -------------------
	// -- RobotList 机器列表集合（分页后 返回的数）
	// -- totalRobotCount 机器总数(有效的总数)
	// -- 必须加上条件》所筛选的机器需要有曝光量或者创单数据，否则不能作为可用的统计数据

	RobotList, totalRobotCount, _ := o.GetAllRobotByMerchantID(ctx, db, page, limit, startTime, endTime, allMerchantIDArr, SalesID)
	// var RobotList = []int64{}

	// for _, v := range strings.Split(SalesID, ",") {
	// saleString += " \"" + v + "\","
	// }

	// if SalesID != "" {
	// 	// tx.Where("o.sales_id in (?)", strings.Split(salesID, ","))
	// }

	var allArr = make(map[string]MyAiFaceCountData)
	var allRobotIDArr = []string{} // 已分页机器列表
	if Type == 1 {
		for _, v := range RobotList {
			if strings.Contains(SalesID, v.RobotName) {
				var item MyAiFaceCountData
				item.RobotName = v.RobotName
				allArr[v.RobotName] = item
				allRobotIDArr = append(allRobotIDArr, v.RobotName) // 用于后面 robot_name in (allRobotIdArr)
			}
		}
	}

	// ------------- 商场分页 -------------
	// -- RobotList 机器列表集合（分页后 返回的数）
	// -- totalRobotCount 机器总数(有效的总数)
	// -- 必须加上条件》所筛选的机器需要有曝光量或者创单数据，否则不能作为可用的统计数据
	// shopList, totalShopCount, _ := o.GetAllShopByMerchantID(ctx, db, page, limit, startTime, endTime, allMerchantIDArr)
	// var allShopArr = make(map[string]interface{})
	// var allShopIDArr = []string{}
	// if Type == 3 {
	// 	for _, v := range shopList {
	// 		var item InitShopInfo
	// 		item.Areas3 = v.Areas3
	// 		item.Name = v.Name
	// 		allArr[v.SalesID] = item
	// 		allRobotIDArr = append(allRobotIDArr, v.RobotName) // 用于后面 robot_name in (allRobotIdArr)
	// 	}
	// }

	// -- page 页数
	// -- limit 分页数
	// -- ShopList 商场列表集合（分页后 返回的数）
	// -- totalShopCount 商场总数(有效的总数)
	// -- 必须加上条件》商场必须拥有机器，并且商场下的机器为有效的机器。（机器必须满足：曝光>0 或者 有创单数）

	// （通过本地机器配置表，获取当前的机器总数）获取已经分配商户的所有零售机器人 [如果使用分页，则只显示指定的机器]
	// 通过Page, Limit实现Robot的分页查询
	// 返回需要分页的机器
	// 要查询的数据
	// 获取之前的商品补货数据

	tx1 := db.Table(models.MaOrder{}.TableName()+" as o").
		Joins("left join "+models.MaRobot{}.TableName()+" as r on r.sales_id = o.sales_id").
		Joins("left join "+models.MaMerchantConfig{}.TableName()+" as m on m.id = o.merchant_id").
		Where("o.order_status in ?", []int{1, 3, 4, 5, 6}).
		Where("o.add_time between ? and ?", startTime, endTime)

	tx := db.Table(models.MaOrder{}.TableName()+" as o").
		Joins("left join "+models.MaRobot{}.TableName()+" as r on r.sales_id = o.sales_id").
		Joins("left join "+models.MaMerchantConfig{}.TableName()+" as m on m.id = o.merchant_id").
		Where("o.order_status in ?", []int{1, 3, 4, 5, 6}).
		Where("o.add_time between ? and ?", startTime, endTime)

	// 判断是否是分页后的机器值匹配，否则查询全部机器
	var robotWheresting string
	var aifaceWheresting string
	if len(allRobotIDArr) != 0 {
		tx.Where("o.robot_name in  (?)", allRobotIDArr)
		for _, v := range allRobotIDArr {
			robotWheresting += " \"" + v + "\","
			aifaceWheresting += " \"" + v + "\","
		}
		robotWheresting = " and o2.robot_name in  (" + strings.TrimSuffix(robotWheresting, ",") + ")"
		aifaceWheresting = " and s.robot_name in  (" + strings.TrimSuffix(aifaceWheresting, ",") + ")"
	}

	// 判断是否是分页后的商户值匹配，否则查询全部商户
	var merchantWhere string
	if len(allMerchantIDArr) != 0 {
		tx.Where("o.merchant_id in (?)", allMerchantIDArr)
	}
	if len(AllMerchantIDList) > 0 { //没分页全部商户信息
		tx1.Where("o.merchant_id in (?)", AllMerchantIDList)
		merchantWhere = " and o2.merchant_id in  (" + strings.Join(AllMerchantIDList, ",") + ")"
	}
	// 获取合计
	tx1.Select(
		"o.merchant_id", "sum(o.payment_amount) AS gmv",
		"(SELECT sum(payment_amount) FROM ma_order AS o2 WHERE o2.order_status IN (4) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS my_payment_amount", // 成交额
		// "(SELECT sum(discount_amount) AS discount_amount FROM ma_order AS o2 WHERE o2.merchant_id = o.merchant_id AND order_status = 4 " + areaWhere + ") total_dis_count," +
		"(SELECT sum(discount_amount) FROM ma_order AS o2 WHERE o2.order_status IN (4) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS my_discount_amount",                        // 优惠金额
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status IN (6) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS my_refund_order_count",                          // 退款数量
		"(SELECT sum(payment_amount) FROM ma_order AS o2 WHERE o2.order_status IN (6) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS my_refund_order_amount",                     // 退款金额
		"(SELECT count(order_id) AS my_order_count FROM ma_order AS o2 WHERE o2.order_status IN (1,3,4,5,6) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS my_start_order_count", // 创单数
		"(SELECT count(order_id) AS my_order_count FROM ma_order AS o2 WHERE o2.order_status IN (4) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS my_success_order_count",       // 成功支付笔数
		"(SELECT count(order_id) AS my_order_count FROM ma_order AS o2 WHERE o2.order_status IN (7) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS my_failed_order_count",        // 失败订单数
		"(SELECT count(order_id) AS my_order_count FROM ma_order AS o2 WHERE o2.order_status IN (1,3) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS my_not_pay_order_count",     // 未支付订单数
		"(SELECT count(count_data) AS my_order_count FROM ma_order AS o2 WHERE o2.order_status IN (1,3,4,6) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS my_goods_count",       // 商品数量
		"(SELECT sum(face_count) FROM ma_ai_service_face_count AS o2 WHERE o2.start_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS face_count",                                              // 总的曝光量
		"(SELECT sum(face_count0) FROM ma_ai_service_face_count AS o2 WHERE o2.start_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS face_count0",                                            // 前的曝光量
		"(SELECT sum(face_count1) FROM ma_ai_service_face_count AS o2 WHERE o2.start_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS face_count1",                                            // 左的曝光量
		"(SELECT sum(face_count2) FROM ma_ai_service_face_count AS o2 WHERE o2.start_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+robotWheresting+") AS face_count2",                                            // 右的曝光量
		"(SELECT sum(click_num) FROM ma_goods_click AS o2 WHERE o2.start_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+merchantWhere+") AS click_num",                                                                          // 点击数
		"(SELECT count(DISTINCT unique_id) FROM ma_wechat_rate AS o2 WHERE o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"') AS pay_num",                                                                                    // 支付人数
	).Take(&TotalCount)

	// 获取所有数据
	tx.Group(myGroup).Select(
		"o.merchant_id", "m.user_name", "o.sales_id", "o.order_status", "r.robot_name", "r.sales_id", "r.areas3",
		"sum(o.payment_amount) AS gmv",
		"(SELECT sum(payment_amount) FROM ma_order AS o2 WHERE order_status IN (4) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"' AND o2.sales_id = o.sales_id) AS my_payment_amount",                          // 成交额
		"(SELECT sum(discount_amount) FROM ma_order AS o2 WHERE order_status IN (4) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"' AND o2.sales_id = o.sales_id) AS my_discount_amount",                        // 优惠金额
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE order_status IN (6) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"' AND o2.sales_id = o.sales_id) AS my_refund_order_count",                          // 退款数量
		"(SELECT sum(payment_amount) FROM ma_order AS o2 WHERE order_status IN (6) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"' AND o2.sales_id = o.sales_id) AS my_refund_order_amount",                     // 退款金额
		"(SELECT count(order_id) AS my_order_count FROM ma_order AS o2 WHERE order_status IN (1,3,4,5,6) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"' AND o2.sales_id = o.sales_id) AS my_start_order_count", // 创单数
		"(SELECT count(order_id) AS my_order_count FROM ma_order AS o2 WHERE order_status IN (4) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"' AND o2.sales_id = o.sales_id) AS my_success_order_count",       // 成功支付笔数
		"(SELECT count(order_id) AS my_order_count FROM ma_order AS o2 WHERE order_status IN (7) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"' AND o2.sales_id = o.sales_id) AS my_failed_order_count",        // 失败订单数
		"(SELECT count(order_id) AS my_order_count FROM ma_order AS o2 WHERE order_status IN (1,3) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"' AND o2.sales_id = o.sales_id) AS my_not_pay_order_count",     // 未支付订单数
		"(SELECT count(count_data) AS my_order_count FROM ma_order AS o2 WHERE order_status IN (1,3,4,6) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"' AND o2.sales_id = o.sales_id) AS my_goods_count",       // 商品数量
		"(SELECT sum(s.face_count) FROM ma_ai_service_face_count AS s WHERE s.sales_id = o.sales_id AND s.start_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+aifaceWheresting+") AS face_count",                        // 总的曝光量
		"(SELECT sum(s.face_count0) FROM ma_ai_service_face_count AS s WHERE s.sales_id = o.sales_id AND s.start_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+aifaceWheresting+") AS face_count0",                      // 前的曝光量
		"(SELECT sum(s.face_count1) FROM ma_ai_service_face_count AS s WHERE s.sales_id = o.sales_id AND s.start_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+aifaceWheresting+") AS face_count1",                      // 左的曝光量
		"(SELECT sum(s.face_count2) FROM ma_ai_service_face_count AS s WHERE s.sales_id = o.sales_id AND s.start_time BETWEEN '"+startTime+"' AND '"+endTime+"'"+aifaceWheresting+") AS face_count2",                      // 右的曝光量
		"(SELECT sum(g.click_num) FROM ma_goods_click AS g WHERE g.sales_id = o.sales_id and g.start_time BETWEEN '"+startTime+"' AND '"+endTime+"') AS click_num",                                                        // 点击数
		"(SELECT count(DISTINCT w.unique_id) FROM ma_wechat_rate AS w WHERE w.sales_id = o.sales_id and w.add_time BETWEEN '"+startTime+"' AND '"+endTime+"') AS pay_num",
	).Find(&ResultList)

	//获取grpc客户端
	deviceClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		logx.Error(context.Background(), "grpc device admin client error", logx.Err(clientErr))
		err = clientErr
		return
	}
	SystemAdminClient, clientErr := client.GetSystemAdminClient()
	if clientErr != nil {
		logx.Error(context.Background(), "grpc system admin client error", logx.Err(clientErr))
		err = clientErr
		return
	}

	//  获取机器的商品信息 【 ***** 】
	var DataMap = make(map[string][]schema.OrderStatData)
	// 参数：res 是全部查询到的结果集
	result, _ := o.GetGoodsInfo(ctx, db, ResultList)
	if Type == 2 {
		// 商户
		for _, v := range result {
			DataMap[v.UserName] = append(DataMap[v.UserName], v) // 商户名 => 订单数据
		}
	} else if Type == 3 { // 3 - 商场
		deviceReq := &devicec.LocationListReq{}
		deviceRes, err := deviceClient.LocationList(context.Background(), deviceReq)
		var LocationMap = make(map[string]string)
		if deviceRes != nil && deviceRes.Code == 0 && err == nil {
			for _, v := range deviceRes.List {
				LocationMap[v.Id] = v.Name
			}
		}
		for _, v := range result {
			// grpc 获取设备商场名称
			if _, ok := LocationMap[v.Areas3]; ok {
				TagName := LocationMap[v.Areas3]
				DataMap[TagName] = append(DataMap[TagName], v) // 商场名 => 订单数据
			}
		}
	}

	// a. 获取人流数据
	personData, _ := dao.FaceCount{}.GetFaceCountList(ctx, dal.Q, []string{}, strings.Join(allRobotIDArr, ","), startTime, endTime, 0, 3, 0, 0)
	for _, v := range personData {
		delete(allArr, v.RobotName) // 删除一个map
	}
	// b. 获取点击数据
	var clickArr []string // 数组3 -- 先有人流数，后有点击数
	var clickArr1 = make(map[string]int)
	click_data, _ := o.getClickOfRobot()
	for _, v := range click_data {
		clickArr = append(clickArr, v.RobotName)
		clickArr1[v.RobotName] = v.ClickNum // 机器存储点击数
	}

	// 机器如果有点击数，则写入点击数
	var personDataSalesid = make(map[string]MyAiFaceCountData) // 数组1
	for _, v := range personData {
		var item MyAiFaceCountData
		if lo.Contains(clickArr, v.RobotName) {
			item.RobotName = v.RobotName
			item.FaceCount = v.FaceCount
			item.FaceCount0 = v.FaceCount0
			item.FaceCount1 = v.FaceCount1
			item.FaceCount2 = v.FaceCount2
			item.FaceCount3 = v.FaceCount3
			item.ClickNum = clickArr1[v.RobotName]
			personDataSalesid[v.RobotName] = item
		} else {
			item.RobotName = v.RobotName
			item.FaceCount = v.FaceCount
			item.FaceCount0 = v.FaceCount0
			item.FaceCount1 = v.FaceCount1
			item.FaceCount2 = v.FaceCount2
			item.FaceCount3 = v.FaceCount3
			item.ClickNum = 0
			personDataSalesid[v.RobotName] = item
		}
	}

	var DataArr = make(map[string]string) // 数组2 机器名称 =》
	if Type == 2 {                        // 商户
		for _, val := range DataMap {
			for _, v := range val {
				DataArr[v.RobotName] = v.SalesID
			}
		}
	} else {
		for _, v := range ResultList { // 1（机器） 、 3 （商场）
			DataArr[v.RobotName] = v.SalesID
		}
	}

	// 取差集
	var intersect = make(map[string]MyAiFaceCountData)
	compareDiff, _ := lo.Difference(lo.Keys(personDataSalesid), lo.Keys(DataArr))
	if len(compareDiff) > 0 {
		// 1.获取左边全部的值，但是这里还无法获取到差异的值。需要进行循环操作才能获得
		leftVal := lo.Values(personDataSalesid)
		// 2.根据比较的值进行筛选出差异的值
		// for mkey, val := range compareDiff { //比如左右获得差异key为： DDretail007,DDretail011
		for _, val := range compareDiff { //比如左右获得差异key为： DDretail007,DDretail011

			// for k, value := range leftVal {
			for _, value := range leftVal {
				// if k == mkey {
				if value.RobotName == val {
					intersect[val] = value
				}
			}
		}
	}
	// data_arr的数据填充到intersect
	for _, v := range allArr {
		if _, ok := DataArr[v.RobotName]; !ok {
			intersect[v.RobotName] = v
		}
	}

	// 获取位置列表Map, 组装格式：Map[id] = name
	deviceReq := &devicec.LocationListReq{}
	deviceRes, err := deviceClient.LocationList(context.Background(), deviceReq)
	var LocationMap = make(map[string]string)
	if deviceRes != nil && deviceRes.Code == 0 && err == nil {
		for _, v := range deviceRes.List {
			LocationMap[v.Id] = v.Name
		}
	}

	for key, val := range intersect {
		var location_name string = ""
		var merchantName string = ""
		//grpc 设备后台获取机器的服务电话
		req := &devicec.DeviceDetailReq{}
		req.RobotId = val.RobotName
		myres, err := deviceClient.DeviceDetail(context.Background(), req)
		salesID := ""
		if myres != nil && myres.Code == 0 && err == nil {
			location_id := myres.Device.LocationId
			// 获取每台机器的商户ID
			merchantID := myres.Device.MerchantId // 商户ID
			salesID = myres.Device.IdentificationCode
			// 根据商户ID，获取商户名称
			req := &system_admin.MerchantInfoReq{}
			req.MerchantId = merchantID
			res, err := SystemAdminClient.MerchantInfo(context.Background(), req)
			if res != nil && res.Code == 0 && err == nil {
				merchantName = res.MerchantName
			}
			if location_id != "" {
				// 获取商场名称
				if _, ok := LocationMap[location_id]; ok {
					location_name = LocationMap[location_id]
				}
			}
		}
		//订单信息
		var arr schema.OrderStatData
		arr.UserName = merchantName
		arr.SalesID = salesID
		arr.OrderStatus = 0
		arr.RobotName = key
		arr.MyOrderCount = 0
		arr.Gmv = 0
		arr.MyPaymentAmount = 0
		arr.MyRefundOrderCount = 0
		arr.MyRefundOrderAmount = 0
		arr.MyStartOrderCount = 0
		arr.MySuccessOrderCount = 0
		arr.MyAllOrderCount = 0
		arr.MyFailedOrderCount = 0
		arr.MyNotPayOrderCount = 0
		arr.MyGoodsCount = 0
		arr.PayNum = 0
		arr.FaceCount = val.FaceCount
		arr.FaceCount0 = val.FaceCount0
		arr.FaceCount1 = val.FaceCount1
		arr.FaceCount2 = val.FaceCount2
		arr.FaceCount3 = val.FaceCount3
		arr.ClickNum = val.ClickNum
		arr.OrderPercent = 0
		arr.PersonCount = 0
		arr.PersonCountPercent = 0
		arr.GoodsInfo = []schema.GoodDataType{}

		// 组装成数组
		// 判断是否是商场、商户
		if Type == 2 { // 商户
			DataMap[merchantName] = append(DataMap[merchantName], arr)
		} else if Type == 3 { // 商场
			if location_name != "" {
				DataMap[location_name] = append(DataMap[location_name], arr)
			} else {
				DataMap["未分配区域机器"] = append(DataMap["未分配区域机器"], arr)
			}
		} else {
			ResultList = append(ResultList, arr) // 默认机器
		}
	}
	if Type == 2 || Type == 3 { // 商户 商场
		var returnData = []map[string]interface{}{}
		for name, data := range DataMap {
			// 对n进行排序
			sort.Slice(data, func(i, j int) bool {
				return data[i].RobotName < data[j].RobotName
			})
			var item = make(map[string]interface{})
			item["data"] = data
			item["name"] = name
			returnData = append(returnData, item)
		}
		myresult = returnData
	} else { // 机器
		sort.Slice(ResultList, func(i, j int) bool {
			return ResultList[i].RobotName < ResultList[j].RobotName
		})
		myresult = ResultList
	}

	return myresult, totalRobotCount, TotalCount, err
}

// 出货成功
type RobotDailySuccessOrderS struct {
	RobotName         string  `json:"robot_name"`
	SuccessOrderCount int     `json:"success_order_count"`
	PaymentAmount     float64 `json:"payment_amount"`
}

// 退款
type RobotDailyRefundOrderS struct {
	RobotName         string  `json:"robot_name"`
	RefundOrderCount  int     `json:"refund_order_count"`
	RefundOrderAmount float64 `json:"refund_order_amount"`
}

// 创单
type RobotDailyCreateOrderS struct {
	RobotName       string `json:"robot_name"`
	StartOrderCount int    `json:"start_order_count"`
}

// 未支付
type RobotDailyNotPaidOrderS struct {
	RobotName        string `json:"robot_name"`
	NotPayOrderCount int    `json:"not_pay_order_count"`
}

// 失败订单
type RobotDailyFailedOrderS struct {
	RobotName        string `json:"robot_name"`
	FailedOrderCount int    `json:"failed_order_count"`
}

/**
 *
 * 数据筛查
 *	-- (基于实时数据)
 *	-- 返回筛查结果
 */
func (o OrderStatisticService) GetHeatMapInfo(ctx context.Context, db *gorm.DB,
	startTime, endTime, SalesID string, page, limit int,
) (myresult []schema.OrderStatData, totalRobotCount int64, err error) {
	if startTime != "" && endTime != "" {
		if len(endTime) == 10 {
			endTime = carbon.Parse(endTime).EndOfDay().ToDateTimeString()
		}
	} else { // 默认今日
		startTime = carbon.Now().StartOfDay().ToDateTimeString()
		endTime = carbon.Now().EndOfDay().ToDateTimeString()
	}

	var orderList []schema.OrderStatData
	// 获取之前的商品补货数据
	tx := db.Table(models.MaOrder{}.TableName()+" as o").
		Joins("left join "+models.MaRobot{}.TableName()+" as r on r.sales_id = o.sales_id").
		Where("o.order_status in ?", []int{1, 3, 4, 5, 6}).
		Where("o.add_time between ? and ?", startTime, endTime)

	var allRobotIDArr = []string{}
	if SalesID == "" {
		// RobotList 先获取机器集合
		RobotList, _, _ := o.GetAllRobotByMerchantID(ctx, db, page, limit, startTime, endTime, []string{}, "")
		for _, v := range RobotList {
			allRobotIDArr = append(allRobotIDArr, v.RobotName)
		}
		if len(allRobotIDArr) > 0 {
			tx = tx.Where("o.robot_name in (?)", allRobotIDArr)
		}
	} else {
		robotInfo, _ := dao.Robot{}.RobotDetail(ctx, db, "", "", SalesID)
		if robotInfo == nil || robotInfo.ID == "" {
			return
		}
		tx = tx.Where("o.robot_name = ?", robotInfo.RobotName)
		allRobotIDArr = append(allRobotIDArr, robotInfo.RobotName)
	}
	if len(allRobotIDArr) == 0 {
		return
	}
	SystemAdminClient, clientErr := client.GetSystemAdminClient()
	if clientErr != nil {
		return
	}

	tx.Group("o.robot_name").
		Select(
			"o.merchant_id", "o.sales_id", "o.order_status", "r.robot_name", "r.areas3",
			"sum(o.payment_amount) AS gmv",
			"(SELECT count(count_data) AS my_order_count FROM ma_order AS o2 WHERE order_status IN (1,3,4,6) AND o2.add_time BETWEEN '"+startTime+"' AND '"+endTime+"' AND o2.robot_name = o.robot_name) AS my_goods_count", // 商品数量
			"(SELECT count(DISTINCT w.unique_id) FROM ma_wechat_rate w WHERE w.robot_name = o.robot_name AND w.add_time BETWEEN '"+startTime+"' AND '"+endTime+"') AS pay_num",
		)
	tx.Find(&orderList)

	var RobotDailySuccessOrder []RobotDailySuccessOrderS
	var RobotDailyRefundOrder []RobotDailyRefundOrderS
	var RobotDailyCreateOrder []RobotDailyCreateOrderS
	var RobotDailyNotPaidOrder []RobotDailyNotPaidOrderS
	var RobotDailyFailedOrder []RobotDailyFailedOrderS
	var merchantNameMapRes *system_admin.MerchantNameRsp
	RobotDailySuccessOrderMap := make(map[string]RobotDailySuccessOrderS)
	RobotDailyRefundOrderMap := make(map[string]RobotDailyRefundOrderS)
	RobotDailyCreateOrderMap := make(map[string]RobotDailyCreateOrderS)
	RobotDailyNotPaidOrderMap := make(map[string]RobotDailyNotPaidOrderS)
	RobotDailyFailedOrderMap := make(map[string]RobotDailyFailedOrderS)
	if len(orderList) > 0 {
		// 出货成功数量、出货成功金额
		db.Model(&models.MaOrder{}).
			Where("order_status = 4 and add_time between ? and ?", startTime, endTime).
			Group("robot_name").
			Select("robot_name,count(order_id) as success_order_count, sum(payment_amount) as payment_amount").
			Find(&RobotDailySuccessOrder)
		for _, v := range RobotDailySuccessOrder {
			RobotDailySuccessOrderMap[v.RobotName] = v
		}
		// 退款数量、退款金额
		db.Model(&models.MaOrder{}).
			Where("order_status = 6 and add_time between ? and ?", startTime, endTime).
			Group("robot_name").
			Select("robot_name,count(order_id) as refund_order_count, sum(payment_amount) as refund_order_amount").
			Find(&RobotDailyRefundOrder)
		for _, v := range RobotDailyRefundOrder {
			RobotDailyRefundOrderMap[v.RobotName] = v
		}
		// 创单数
		db.Model(&models.MaOrder{}).
			Where("order_status in (1,3,4,5,6) and add_time between ? and ?", startTime, endTime).
			Group("robot_name").
			Select("robot_name,count(order_id) as start_order_count").
			Find(&RobotDailyCreateOrder)
		for _, v := range RobotDailyCreateOrder {
			RobotDailyCreateOrderMap[v.RobotName] = v
		}
		// 未支付数
		db.Model(&models.MaOrder{}).
			Where("order_status in (1,3) and add_time between ? and ?", startTime, endTime).
			Group("robot_name").
			Select("robot_name,count(order_id) as not_pay_order_count").
			Find(&RobotDailyNotPaidOrder)
		for _, v := range RobotDailyNotPaidOrder {
			RobotDailyNotPaidOrderMap[v.RobotName] = v
		}
		// 失败订单
		db.Model(&models.MaOrder{}).
			Where("order_status = 7 and add_time between ? and ?", startTime, endTime).
			Group("robot_name").
			Select("robot_name,count(order_id) as failed_order_count").
			Find(&RobotDailyFailedOrder)
		for _, v := range RobotDailyFailedOrder {
			RobotDailyFailedOrderMap[v.RobotName] = v
		}
		// 商户名称
		var merchantIds []string
		for _, v := range orderList {
			merchantIds = append(merchantIds, v.MerchantID)
		}
		req := &system_admin.MerchantNameReq{
			MerchantIds: lo.Uniq(merchantIds),
		}
		merchantNameMapRes, err = SystemAdminClient.MerchantName(ctx, req)
		if err != nil {
			return
		}
	}

	// 曝光量
	personData, _ := dao.FaceCount{}.GetFaceCountList(ctx, dal.Q, []string{}, strings.Join(allRobotIDArr, ","),
		startTime, endTime, 0, 3, 0, 0)
	// 点击量
	var clickCountMap = make(map[string]int)
	clickData, _ := o.getClickOfRobot()
	for _, v := range clickData {
		clickCountMap[v.RobotName] = v.ClickNum // 机器 => 点击数
	}

	// 机器如果有点击数，则写入点击数
	var RobotFacecountMap = make(map[string]MyAiFaceCountData)
	for _, v := range personData {
		var item MyAiFaceCountData
		item.FaceCount = v.FaceCount
		item.FaceCount0 = v.FaceCount0
		item.FaceCount1 = v.FaceCount1
		item.FaceCount2 = v.FaceCount2
		item.FaceCount3 = v.FaceCount3
		if _, ok := clickCountMap[v.RobotName]; ok {
			item.ClickNum = clickCountMap[v.RobotName]
		}
		RobotFacecountMap[v.RobotName] = item
	}

	var OrderRobot = make(map[string]ItemSalesID)
	for k, v := range orderList {
		if _, ok := RobotFacecountMap[v.RobotName]; ok {
			orderList[k].FaceCount = RobotFacecountMap[v.RobotName].FaceCount
			orderList[k].FaceCount0 = RobotFacecountMap[v.RobotName].FaceCount0
			orderList[k].FaceCount1 = RobotFacecountMap[v.RobotName].FaceCount1
			orderList[k].FaceCount2 = RobotFacecountMap[v.RobotName].FaceCount2
			orderList[k].FaceCount3 = RobotFacecountMap[v.RobotName].FaceCount3
			orderList[k].ClickNum = RobotFacecountMap[v.RobotName].ClickNum
		}
		if _, ok := RobotDailySuccessOrderMap[v.RobotName]; ok {
			orderList[k].MySuccessOrderCount = RobotDailySuccessOrderMap[v.RobotName].SuccessOrderCount
			orderList[k].MyPaymentAmount = RobotDailySuccessOrderMap[v.RobotName].PaymentAmount
		}
		if _, ok := RobotDailyRefundOrderMap[v.RobotName]; ok {
			orderList[k].MyRefundOrderCount = RobotDailyRefundOrderMap[v.RobotName].RefundOrderCount
			orderList[k].MyRefundOrderAmount = RobotDailyRefundOrderMap[v.RobotName].RefundOrderAmount
		}
		if _, ok := RobotDailyCreateOrderMap[v.RobotName]; ok {
			orderList[k].MyStartOrderCount = RobotDailyCreateOrderMap[v.RobotName].StartOrderCount
		}
		if _, ok := RobotDailyNotPaidOrderMap[v.RobotName]; ok {
			orderList[k].MyNotPayOrderCount = RobotDailyNotPaidOrderMap[v.RobotName].NotPayOrderCount
		}
		if _, ok := RobotDailyFailedOrderMap[v.RobotName]; ok {
			orderList[k].MyFailedOrderCount = RobotDailyFailedOrderMap[v.RobotName].FailedOrderCount
		}
		if merchantName, ok := merchantNameMapRes.MerchantNameMap[v.MerchantID]; ok {
			orderList[k].UserName = merchantName
		}
		var item ItemSalesID
		item.SalesID = v.SalesID
		OrderRobot[v.RobotName] = item
	}

	// 取差集
	var differenceRobot = make(map[string]MyAiFaceCountData)
	compareDiff, _ := lo.Difference(lo.Keys(RobotFacecountMap), lo.Keys(OrderRobot)) // 获取差集
	if len(compareDiff) != 0 {
		leftVal := lo.Values(RobotFacecountMap)
		for mkey, val := range compareDiff { //比如左右获得差异key为： DDretail007,DDretail011
			for k, value := range leftVal {
				if k == mkey {
					differenceRobot[val] = value
				}
			}
		}
	}

	// grpc 连接验证
	deviceClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		logx.Error(context.Background(), "grpc device client error", logx.Err(clientErr))
		return
	}
	for robotName, val := range differenceRobot {
		merchantName := ""
		salesID := ""
		// 获取机器详细信息
		req := &devicec.DeviceDetailReq{}
		req.RobotId = val.RobotName
		deviceRsp, deviceRspErr := deviceClient.DeviceDetail(context.Background(), req)
		if deviceRspErr == nil && deviceRsp != nil && deviceRsp.Code == 0 && deviceRsp.Device != nil {
			salesID = deviceRsp.Device.IdentificationCode
			req := &system_admin.MerchantInfoReq{}
			req.MerchantId = deviceRsp.Device.MerchantId // 获取商户名称
			merchantRsp, merchantRspErr := SystemAdminClient.MerchantInfo(context.Background(), req)
			if merchantRspErr == nil && merchantRsp != nil && merchantRsp.Code == 0 {
				merchantName = merchantRsp.MerchantName
			}
		}

		var arr schema.OrderStatData
		arr.UserName = merchantName
		arr.RobotName = robotName
		arr.SalesID = salesID
		arr.FaceCount = val.FaceCount
		arr.FaceCount0 = val.FaceCount0
		arr.FaceCount1 = val.FaceCount1
		arr.FaceCount2 = val.FaceCount2
		arr.FaceCount3 = val.FaceCount3
		arr.ClickNum = val.ClickNum
		orderList = append(orderList, arr)
	}

	return orderList, totalRobotCount, err
}

// 定义ItemSalesID
type ItemSalesID struct {
	SalesID string `json:"sales_id"`
}

type InitSalesInfo struct {
	SalesID    string  `json:"sales_id"`
	RobotName  string  `json:"robot_name"`
	FaceCount  float64 `json:"face_count"`
	FaceCount0 float64 `json:"face_count0"`
	FaceCount1 float64 `json:"face_count1"`
	FaceCount2 float64 `json:"face_count2"`
	FaceCount3 float64 `json:"face_count3"`
	ClickNum   int     `json:"click_num"`
}

type InitMerchantInfo struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

// GetRepeatUserDetail 复购用户详情列表
func (o OrderStatisticService) GetRepeatUserDetail(ctx context.Context, db *gorm.DB, page, limit int, uniqueID, startTime, endTime,
	salesID, goodsName, areas1, areas2, areas3 string) (data interface{}, count int64, err error) {
	tx := db.Table(models.MaWechatRate{}.TableName()+" as w").
		Joins("left join "+models.MaOrder{}.TableName()+" as o on o.end_out_trade_no = w.out_trade_no").
		Where("w.unique_id = ?", uniqueID)
	if startTime != "" && endTime != "" {
		tx.Where("w.add_time between ? and ?", startTime, endTime)
	}
	tx.Count(&count)
	var Res []struct {
		Date           string    `json:"date"`
		Type           string    `json:"type"`
		UniqueID       string    `json:"unique_id"`
		GoodsID        string    `json:"goods_id"`
		SalesID        string    `json:"sales_id"`
		RobotName      string    `json:"robot_name"`
		PaymentAmount  string    `json:"payment_amount"`
		OutTradeNo     string    `json:"out_trade_no"`
		AddTime        time.Time `json:"-"`
		AddTimeFomated string    `json:"add_time"`
		PaymentID      string    `json:"payment_id"`
		Areas3         string    `json:"areas3"`
		GoodsName      string    `json:"goods_name"`
	}
	field := "date_format(w.add_time, '%Y-%m-%d') as date, w.type, w.unique_id, w.goods_id, w.sales_id, o.robot_name, o.payment_amount, " +
		"o.out_trade_no, o.add_time, o.payment_id, o.areas3, json_extract_c(o.count_data, '$.GoodsName') AS goods_name"
	helper.Gorm{}.Paginate(tx, page, limit).Select(field).Find(&Res)
	for k, v := range Res {
		json.Unmarshal([]byte("\""+Res[k].GoodsName+"\""), &Res[k].GoodsName)
		addTimeFormated, _ := models.DateTime(v.AddTime).MarshalDateTime()
		Res[k].AddTimeFomated = string(addTimeFormated)
	}
	return Res, count, nil
}

type RepeatUserStruct struct {
	Date          string  `json:"date"`
	UniqueID      string  `json:"unique_id"`
	PayCount      float64 `json:"pay_count"`
	PaymentAmount string  `json:"payment_amount"`
	AddTime       string  `json:"add_time"`
	PaymentID     string  `json:"payment_id"`
}

// GetRepeatUser 复购用户
func (o OrderStatisticService) GetRepeatUser(ctx context.Context, db *gorm.DB, merchantID string, page, limit int, uniqueID, startTime, endTime,
	salesID, goodsName, areas1, areas2, areas3 string, shopIDList []string) (data interface{}, PayUser, RepeatUser, Count int, err error) {
	var count int64
	tx := db.Table(models.MaOrder{}.TableName() + " as o").
		Where("o.order_status in (4,6) and o.end_out_trade_no != ''") //4出货成功，6退款
	if startTime != "" && endTime != "" {
		startTime = carbon.Parse(startTime).StartOfDay().ToDateTimeString()
		endTime = carbon.Parse(endTime).EndOfDay().ToDateTimeString()
		tx.Where("o.add_time between ? and ?", startTime, endTime)
	}

	merchantIDs, err1 := common.Order{}.GetMerchantChildren(ctx, merchantID, shopIDList)
	if err1 != nil {
		err = err1
		return
	}
	tx.Where("o.merchant_id in (?)", merchantIDs)
	if salesID != "" {
		tx.Where("o.sales_id in (?)", strings.Split(salesID, ","))
	}
	if areas1 != "" {
		tx.Where("o.areas1 in (?)", strings.Split(areas1, ","))
	}
	if areas2 != "" {
		tx.Where("o.areas2 in (?)", strings.Split(areas2, ","))
	}
	if areas3 != "" {
		tx.Where("o.areas3 in (?)", strings.Split(areas3, ","))
	}
	if goodsName != "" {
		unicodeName, _ := common.UnicodeEncode(goodsName)
		tx.Where("o.count_data like '%" + strings.ReplaceAll(unicodeName, "\\", "_") + "%'")
	}
	tx.Count(&count)
	tx.Joins("join " + models.MaWechatRate{}.TableName() + " as w on o.end_out_trade_no = w.out_trade_no and w.unique_id != ''")
	var Res = []RepeatUserStruct{}
	field := " date_format(o.add_time, '%Y-%m-%d') as date, w.unique_id, " +
		"sum(w.count) as pay_count"
	tx.Select(field).Group("date,w.unique_id").Order("date asc").Find(&Res)
	var UniqueIDResMap = make(map[string][]RepeatUserStruct)
	for _, v := range Res {
		UniqueIDResMap[v.UniqueID] = append(UniqueIDResMap[v.UniqueID], v)
	}
	var ArrOne = []struct {
		UniqueID string  `json:"unique_id"`
		Count    int     `json:"count"`
		PayCount float64 `json:"pay_count"`
	}{}
	for k, v := range UniqueIDResMap {
		var PayCount float64
		for _, v1 := range v {
			PayCount += v1.PayCount
		}
		if len(v) > 1 {
			ArrOne = append(ArrOne, struct {
				UniqueID string  `json:"unique_id"`
				Count    int     `json:"count"`
				PayCount float64 `json:"pay_count"`
			}{
				UniqueID: k,
				Count:    len(v),
				PayCount: PayCount,
			})
		}
	}
	PayUser = len(UniqueIDResMap)
	RepeatUser = len(ArrOne)
	Count = len(ArrOne)
	start, end := common.SlicePage(page, limit, len(ArrOne))
	PageRes := ArrOne[start:end]
	return PageRes, PayUser, RepeatUser, Count, nil
}

func (o OrderStatisticService) GetGoodsSoldCount(ctx context.Context, db *gorm.DB, merchantID, salesID string, provinceID, cityID, locationID, countyID string, shopIDList []string, startTime, endTime string, page, limit int) (ReturnData []GoodsSoldCountReturn, totalAmount float64, totalSoldCount, count int64, err error) {
	robotList, _, _ := dao.Robot{}.RobotList(ctx, db, "", "", "", salesID, "", "", "", "")
	var robotNameList = []string{}
	for _, v := range robotList {
		robotNameList = append(robotNameList, v.RobotName)
	}
	robotIDs := strings.Join(robotNameList, ",")
	ReturnData, totalAmount, totalSoldCount, count, err = o.GoodsTransactionAmountDescendingList(ctx, db, merchantID, robotIDs, provinceID, cityID, locationID, countyID, shopIDList, startTime, endTime, page, limit)
	return
}

type GoodsSoldCountReturn struct {
	MerchantID string  `json:"-"`                  // 商户id
	GoodsName  string  `json:"goods_name"`         // 商品名称
	GoodsID    string  `json:"goods_id"`           // 商品ID
	Count      int64   `json:"count"`              // 总销售数量
	TotalMoney float64 `json:"total_money"`        // 总销售额
	Name       string  `gorm:"-" json:"name"`      // 商场名称
	UserName   string  `gorm:"-" json:"user_name"` // 商户名称
	LocationID string  `json:"-"`                  // 商场id
}

func (o OrderStatisticService) GoodsTransactionAmountDescendingList(ctx context.Context, db *gorm.DB, merchantID, robotID string, provinceID, cityID, locationID, countyID string, shopIDList []string, startTime, endTime string, page, limit int) (ReturnData []GoodsSoldCountReturn, totalAmount float64, totalSoldCount, count int64, err error) {
	merchantIDs, err := common.Order{}.GetMerchantChildren(ctx, merchantID, shopIDList)
	if err != nil {
		return
	}
	start := carbon.Parse(startTime).Timestamp()
	end := carbon.Parse(endTime).EndOfDay().Timestamp()
	list, count, _, err := dao.NewGoodsDailyReport(ctx, db).
		WithMerchantID(strings.Join(merchantIDs, ",")).
		WithRobotID(robotID).
		WithProvinceID(provinceID).
		WithCityID(cityID).
		WithLocationID(locationID).
		WithTimePeriod(start, end).
		WithPaginate(page, limit).
		WithGroupType(6).     // 按商品分组
		WithOrderType("4_1"). // 实付金额倒序
		List()
	if err != nil {
		return
	}
	for _, v := range list {
		locationID := ""
		if v.LocationID != nil {
			locationID = *v.LocationID
		}
		ReturnData = append(ReturnData, GoodsSoldCountReturn{
			MerchantID: *v.MerchantID,
			GoodsName:  *v.GoodsName,
			GoodsID:    *v.GoodsID,
			Count:      *v.TotalPaidOrder,
			TotalMoney: *v.TransactionAmount,
			LocationID: locationID,
		})
	}

	// 获取商户及商场信息
	SystemAdminClient, clientErr := client.GetSystemAdminClient()
	if clientErr != nil {
		err = clientErr
		return
	}
	deviceClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		err = clientErr
		return
	}
	deviceReq := &devicec.LocationListReq{}
	deviceRes, err := deviceClient.LocationList(context.Background(), deviceReq)
	var LocationMap = make(map[string]string)
	if deviceRes != nil && deviceRes.Code == 0 && err == nil {
		for _, v := range deviceRes.List {
			LocationMap[v.Id] = v.Name
		}
	}
	for k, v := range ReturnData {
		json.Unmarshal([]byte("\""+ReturnData[k].GoodsName+"\""), &ReturnData[k].GoodsName)
		req := &system_admin.MerchantInfoReq{}
		req.MerchantId = v.MerchantID
		res, err1 := SystemAdminClient.MerchantInfo(context.Background(), req)
		if res != nil && res.Code == 0 && err1 == nil {
			ReturnData[k].UserName = res.MerchantName
		}

		// grpc 获取设备商场名称
		if _, ok := LocationMap[v.LocationID]; ok {
			ReturnData[k].Name = LocationMap[v.LocationID]
		}

	}
	return
}

type OrderDescTotalCount struct {
	OrderCount               int     `json:"order_count"`
	TotalDisCount            float64 `json:"total_dis_count"`
	TotalMyDiscountAmount    float64 `json:"total_my_discount_amount"` // 兼容open字段差异，临时性策略
	TotalGiveAmount          float64 `json:"total_give_amount"`
	TotalGmv                 float64 `json:"total_gmv"`
	TotalMyPaymentAmount     float64 `json:"total_my_payment_amount"`
	TotalMyRefundOrderCount  int     `json:"total_my_refund_order_count"`
	TotalMyRefundOrderAmount float64 `json:"total_my_refund_order_amount"`
	TotalMyStartOrderCount   int     `json:"total_my_start_order_count"`
	TotalMySuccessOrderCount int     `json:"total_my_success_order_count"`
	TotalMyFailedOrderCount  int     `json:"total_my_failed_order_count"`
	TotalMyNotPayOrderCount  int     `json:"total_my_not_pay_order_count"`
	Totalfacecount           float64 `json:"totalfacecount"`
	Totalfacecount0          float64 `json:"totalfacecount0"`
	Totalfacecount1          float64 `json:"totalfacecount1"`
	Totalfacecount2          float64 `json:"totalfacecount2"`
	Totalfacecount3          float64 `json:"totalfacecount3"`
	TotalClickNum            int     `json:"total_click_num"`
	TotalPayNum              float64 `json:"total_pay_num"`
	TotalRepeatPayNum        float64 `json:"total_repeat_pay_num"`
}

type OrderDescReturn struct {
	Date                string    `json:"date"`
	AddTime             time.Time `json:"-"`
	AddTimeFormated     string    `gorm:"-" json:"add_time"`
	SalesID             string    `json:"sales_id"`
	OrderStatus         int       `json:"order_status"`
	RobotName           string    `json:"robot_name"`
	Gmv                 float64   `json:"gmv"`
	MyPaymentAmount     float64   `json:"my_payment_amount"`
	MyDiscountAmount    float64   `json:"my_discount_amount"`
	MyRefundOrderCount  int       `json:"my_refund_order_count"`
	MyRefundOrderAmount float64   `json:"my_refund_order_amount"`
	MyStartOrderCount   int       `json:"my_start_order_count"`
	MySuccessOrderCount int       `json:"my_success_order_count"`
	MyFailedOrderCount  int       `json:"my_failed_order_count"`
	MyNotPayOrderCount  int       `json:"my_not_pay_order_count"`
	Facecount           float64   `json:"facecount"`
	Facecount0          float64   `json:"facecount0"`
	Facecount1          float64   `json:"facecount1"`
	Facecount2          float64   `json:"facecount2"`
	Facecount3          float64   `json:"facecount3"`
	ClickNum            int       `json:"click_num"`
	PayNum              int       `json:"pay_num"`
	RepeatPayNum        int       `json:"repeat_pay_num"`
}

// 订单概览
func (o OrderStatisticService) OrderDesc(ctx context.Context, db *gorm.DB, merchantID string, page, limit int, startTime, endTime, salesID,
	areas1, areas2, areas3, areas5 string, shopIDList []string) (Res []OrderDescReturn, Count int64, totalCount OrderDescTotalCount, err error) {
	var areaWhere string
	var goodsWhere string
	var wechatWhere string

	if endTime != "" {
		endTime = endTime + " 23:59:59"
	}
	if carbon.Parse(endTime).ToStdTime().Unix() >= time.Now().Unix() {
		endTime = carbon.Now().EndOfDay().ToDateTimeString() //先用今天的结束，方便分页计算，分页后修正为当前时间
	}
	if startTime == "" && endTime == "" {
		startTime = carbon.Now().SubDays(6).StartOfDay().ToDateTimeString()
		endTime = carbon.Now().EndOfDay().ToDateTimeString() //先用今天的结束，方便分页计算，分页后修正为当前时间
	}

	tx := db.Table(models.MaOrder{}.TableName() + " as o").
		Where("o.order_status in (1,2,3,4,5,6)")

		// 筛选商户
	merchantIDs, err1 := common.Order{}.GetMerchantChildren(ctx, merchantID, shopIDList)
	if err1 != nil {
		err = err1
		return
	}
	tx.Where("o.merchant_id in (?)", merchantIDs)

	if len(merchantIDs) > 0 {
		var merchantString string
		for _, v := range merchantIDs {
			merchantString += " \"" + v + "\","
		}
		merchantString = strings.TrimSuffix(merchantString, ",")
		areaWhere += " AND (o2.merchant_id in (" + merchantString + "))"
		goodsWhere += " AND (g.merchant_id in (" + merchantString + "))"
		wechatWhere += " AND (g.id in (" + merchantString + "))"
	}
	// 筛选sales_id 及 地区
	if salesID != "" {
		var saleString string
		for _, v := range strings.Split(salesID, ",") {
			saleString += " \"" + v + "\","
		}
		saleString = strings.TrimSuffix(saleString, ",")
		areaWhere += " and o2.sales_id in (" + saleString + ")"
		goodsWhere += " and g.sales_id in (" + saleString + ")"
		wechatWhere += " and g.sales_id in (" + saleString + ")"
		tx.Where("o.sales_id in (?)", strings.Split(salesID, ","))

		if areas1 != "" {
			tx.Where("o.areas1 in (?)", strings.Split(areas1, ","))
			areaWhere += " and o.areas1 in (" + areas1 + ")"
		}

		if areas2 != "" {
			tx.Where("o.areas2 in (?)", strings.Split(areas2, ","))
			areaWhere += " and o.areas2 in (" + areas2 + ")"
		}

		if areas3 != "" {
			tx.Where("o.areas3 in (?)", strings.Split(areas3, ","))
			areaWhere += " and o.areas3 in (" + areas3 + ")"
			// 根据商场 获取下面对应的机器
			areasSalesList := dao.Robot{}.GetSalesIDByAreas3(ctx, db, strings.Split(areas3, ","))
			// 如果存在
			if len(areasSalesList) > 0 {
				// 把机器拼接处字符串
				var saleString string
				for _, v := range areasSalesList {
					saleString += " \"" + v + "\","
				}
				// 给字符串去除逗号
				saleString = strings.TrimSuffix(saleString, ",")
				areaWhere += " and o2.sales_id in (" + saleString + ")"
				goodsWhere += " and g.sales_id in (" + saleString + ")"
				wechatWhere += " and g.sales_id in (" + saleString + ")"
				tx.Where("o.sales_id in (?)", areasSalesList)
			}
		}
	} else {
		if areas1 != "" {
			tx.Where("o.areas1 in (?)", strings.Split(areas1, ","))
			areaWhere += " and o2.areas1 in (" + areas1 + ")"
		}

		if areas2 != "" {
			tx.Where("o.areas2 in (?)", strings.Split(areas2, ","))
			areaWhere += " and o2.areas2 in (" + areas2 + ")"
		}

		if areas3 != "" {
			tx.Where("o.areas3 in (?)", strings.Split(areas3, ","))
			areaWhere += " and o2.areas3 in (" + areas3 + ")"
			// 没有选择sales_id时，需要吧goods_where的省市区条件加上。 areas_where已经加上。
			//  ---- 根据商场 获取下面对应的机器 ----
			areasSalesList := dao.Robot{}.GetSalesIDByAreas3(ctx, db, strings.Split(areas3, ","))
			// 如果存在
			if len(areasSalesList) > 0 {
				// 把机器拼接处字符串
				var saleString string
				for _, v := range areasSalesList {
					saleString += " \"" + v + "\","
				}
				// 给字符串去除逗号
				saleString = strings.TrimSuffix(saleString, ",")
				areaWhere += " and o2.sales_id in (" + saleString + ")"
				goodsWhere += " and g.sales_id in (" + saleString + ")"
				wechatWhere += " and g.sales_id in (" + saleString + ")"
			}

		}

	}

	// 计算分页日期 倒序
	PageEndTime := carbon.Parse(endTime).SubDays(limit * (page - 1)).ToDateTimeString()
	PageStartTime := carbon.Parse(endTime).SubSeconds((limit*page)*86400 - 1).ToDateTimeString()
	if carbon.Parse(PageEndTime).ToStdTime().Unix() > time.Now().Unix() {
		PageEndTime = carbon.Now().ToDateTimeString()
	}
	// 限制开始时间。
	if carbon.Parse(PageStartTime).ToStdTime().Unix() < carbon.Parse(startTime).ToStdTime().Unix() {
		PageStartTime = carbon.Parse(startTime).ToDateTimeString()
	}

	var partDateReturnMap = make(map[string]dao.FaceCountList)
	diffTime := carbon.Parse(PageEndTime).DiffAbsInSeconds(carbon.Parse(PageStartTime))
	for i := diffTime; i > 0; i = i - 86400 {
		date := carbon.Parse(PageEndTime).SubSeconds(int(i)).ToDateString()
		partDateReturnMap[date] = dao.FaceCountList{
			Date:       date,
			FaceCount:  0,
			FaceCount0: 0,
			FaceCount1: 0,
			FaceCount2: 0,
			FaceCount3: 0,
		}
	}
	// 按天统计曝光量
	FaceCount, _, _ := robot.FaceCount{}.GetFaceCount(ctx, db, merchantID, areas3, startTime, endTime, salesID, shopIDList, define.DAY, false)
	var DateFaceCount = make(map[string]dao.FaceCountList)
	for _, v := range FaceCount {
		var item dao.FaceCountList
		item.Date = v.Date
		item.FaceCount += v.FaceCount
		item.FaceCount0 += v.FaceCount0
		item.FaceCount1 += v.FaceCount1
		item.FaceCount2 += v.FaceCount2
		item.FaceCount3 += v.FaceCount3
		DateFaceCount[v.Date] = item
	}

	tx1 := tx.WithContext(ctx)
	tx.Where("o.add_time between ? and ?", startTime, endTime) //总时间

	// 结果返回
	Res = []OrderDescReturn{}
	var field1, field2 string
	areaWhere1 := areaWhere + " AND (o2.add_time BETWEEN '" + startTime + "' AND '" + endTime + "')"
	goodsWhere1 := goodsWhere + " AND (g.start_time BETWEEN '" + startTime + "' AND '" + endTime + "')"
	wechatWhere1 := wechatWhere + " AND (g.add_time BETWEEN '" + startTime + "' AND '" + endTime + "')"
	field1 = "Count(o.order_id) as order_count," +
		"(SELECT sum(payment_amount) AS payment_amount FROM ma_order AS o2 WHERE 1=1 " + areaWhere1 +
		") AS total_gmv, " +
		"(SELECT sum(discount_amount) AS discount_amount FROM ma_order AS o2 WHERE order_status = 4 " + areaWhere1 +
		") AS total_dis_count, " +
		"(SELECT sum(payment_amount) AS payment_amount FROM ma_order AS o2 WHERE payment_id = 7 AND order_status = 4 " + areaWhere1 +
		") AS total_give_amount, " +
		"(SELECT sum(payment_amount) AS payment_amount FROM ma_order AS o2 WHERE order_status = 4 " + areaWhere1 +
		") AS total_my_payment_amount, " +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE order_status = 4 " + areaWhere1 +
		") AS total_my_success_order_count, " +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE order_status = 6 " + areaWhere1 +
		") AS total_my_refund_order_count, " +
		"(SELECT sum(payment_amount) FROM ma_order AS o2 WHERE order_status = 6 " + areaWhere1 +
		") AS total_my_refund_order_amount, " +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status = 7 " + areaWhere1 +
		") AS total_my_failed_order_count, " +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status in(1,3,4,5,6) " + areaWhere1 +
		") AS total_my_start_order_count, " +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status IN(1,3) " + areaWhere1 +
		") AS total_my_not_pay_order_count, " +
		"(SELECT sum(g.click_num) FROM ma_goods_click AS g WHERE 1=1 " + goodsWhere1 +
		") AS total_click_num, " +
		"(SELECT count(DISTINCT unique_id) FROM ma_wechat_rate AS g WHERE 1=1 " + wechatWhere1 +
		") AS total_pay_num, " +
		"(SELECT 0) AS total_repeat_pay_num"
	tx.Select(field1).Take(&totalCount)

	areaWhere2 := areaWhere + " AND (o2.add_time BETWEEN '" + PageStartTime + "' AND '" + PageEndTime + "')"
	goodsWhere2 := goodsWhere + " AND (g.start_time BETWEEN '" + PageStartTime + "' AND '" + PageEndTime + "')"
	wechatWhere2 := wechatWhere + " AND (g.add_time BETWEEN '" + PageStartTime + "' AND '" + PageEndTime + "')"
	field2 = "o.created_date as date, o.add_time, o.sales_id, o.order_status, r.robot_name, " +
		"sum(o.payment_amount) as gmv, " +
		"(SELECT sum(payment_amount) AS payment_amount FROM ma_order AS o2 WHERE order_status = 4 AND o2.created_date = date " + areaWhere2 +
		") AS my_payment_amount," +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE order_status = 4 AND o2.created_date = date " + areaWhere2 +
		") AS my_success_order_count," +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE order_status = 6 AND o2.created_date = date " + areaWhere2 +
		") AS my_refund_order_count," +
		"(SELECT sum(payment_amount) FROM ma_order AS o2 WHERE order_status = 6 AND o2.created_date = date " + areaWhere2 +
		") AS my_refund_order_amount," +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status = 7 AND o2.created_date = date " + areaWhere2 +
		") AS my_failed_order_count," +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status in(1,3,4,5,6) AND o2.created_date = date " + areaWhere2 +
		") AS my_start_order_count," +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status IN(1,3) AND o2.created_date = date " + areaWhere2 +
		") AS my_not_pay_order_count," +
		"(SELECT sum(g.click_num) FROM ma_goods_click AS g WHERE DATE_FORMAT(g.start_time , '%Y-%m-%d') = date " + goodsWhere2 +
		") AS click_num," +
		"(SELECT count(DISTINCT unique_id) FROM ma_wechat_rate AS g WHERE DATE_FORMAT(g.add_time , '%Y-%m-%d') = date " + wechatWhere2 +
		") AS pay_num," +
		"(SELECT 0) AS repeat_pay_num"
	tx1.Joins("left join "+models.MaRobot{}.TableName()+" r on r.sales_id = o.sales_id").
		Where("o.add_time between ? and ?", PageStartTime, PageEndTime).
		Group("date").
		Order("date desc").
		Limit(-1).
		Select(field2).Find(&Res)

	for _, v := range FaceCount {
		totalCount.Totalfacecount += v.FaceCount
		totalCount.Totalfacecount0 += v.FaceCount0
		totalCount.Totalfacecount1 += v.FaceCount1
		totalCount.Totalfacecount2 += v.FaceCount2
		totalCount.Totalfacecount3 += v.FaceCount3
	}
	var ExistDate = make(map[string]string)
	for k, v := range Res {
		addtimeByte, _ := models.DateTime(v.AddTime).MarshalDateTime()
		Res[k].AddTimeFormated = string(addtimeByte)
		Res[k].Date = string(addtimeByte)[:10]
		if _, ok := DateFaceCount[Res[k].Date]; ok {
			Res[k].Facecount = DateFaceCount[Res[k].Date].FaceCount
			Res[k].Facecount0 = DateFaceCount[Res[k].Date].FaceCount0
			Res[k].Facecount1 = DateFaceCount[Res[k].Date].FaceCount1
			Res[k].Facecount2 = DateFaceCount[Res[k].Date].FaceCount2
			Res[k].Facecount3 = DateFaceCount[Res[k].Date].FaceCount3
			ExistDate[Res[k].Date] = Res[k].Date
		}
	}
	for _, v := range DateFaceCount {
		if _, ok := ExistDate[v.Date]; !ok {
			if _, ok := partDateReturnMap[v.Date]; ok {
				Res = append(Res, OrderDescReturn{
					Date:       v.Date,
					Facecount:  v.FaceCount,
					Facecount0: v.FaceCount0,
					Facecount1: v.FaceCount1,
					Facecount2: v.FaceCount2,
					Facecount3: v.FaceCount3,
				})
			}
		}
	}

	Count = carbon.Parse(endTime).DiffAbsInDays(carbon.Parse(startTime)) + 1

	sort.Slice(Res, func(i, j int) bool {
		return Res[i].Date > Res[j].Date
	})
	if len(Res) > int(Count) {
		Count = int64(len(Res))
	}
	return Res, Count, totalCount, nil
}

type HourOrderDescReturn struct {
	Hour                string  `json:"hour"`
	SalesID             string  `json:"sales_id"`
	OrderStatus         int     `json:"order_status"`
	Gmv                 float64 `json:"gmv"`
	MyPaymentAmount     float64 `json:"my_payment_amount"`
	MyOrderCount        float64 `json:"my_order_count"`
	MyRefundOrderCount  float64 `json:"my_refund_order_count"`
	MyRefundOrderAmount float64 `json:"my_refund_order_amount"`
	MyStartOrderCount   float64 `json:"my_start_order_count"`
	MySuccessOrderCount float64 `json:"my_success_order_count"`
	MyAllOrderCount     float64 `json:"my_all_order_count"`
	MyFailedOrderCount  float64 `json:"my_failed_order_count"`
	MyNotPayOrderCount  float64 `json:"my_not_pay_order_count"`
	Facecount           float64 `json:"facecount"`
	Facecount0          float64 `json:"facecount0"`
	Facecount1          float64 `json:"facecount1"`
	Facecount2          float64 `json:"facecount2"`
	Facecount3          float64 `json:"facecount3"`
	ClickNum            float64 `json:"click_num"`
	PayNum              float64 `json:"pay_num"`
}

// 订单概览 按时
func (o OrderStatisticService) HourOrderDesc(ctx context.Context, db *gorm.DB, merchantID string, page, limit int, date, salesID,
	areas1, areas2, areas3, areas5 string, shopIDList []string) (data interface{}, err error) {
	var areaWhere string
	var goodsWhere string
	var personWhere string
	var wechatWhere string
	var startTime string
	var endTime string
	tx := db.Table(models.MaOrder{}.TableName() + " as o").
		Where("o.order_status in (1,2,3,4,5,6)")
	if date != "" {
		startTime = date + " 00:00:00"
		endTime = date + " 23:59:59"
	} else { //默认当天
		date = carbon.Now().ToDateString()
		startTime = carbon.Now().StartOfDay().ToDateTimeString()
		endTime = carbon.Now().ToDateTimeString()
	}
	tx.Where("o.add_time between ? and ?", startTime, endTime)

	areaWhere = " AND (o2.add_time BETWEEN '" + startTime + "' AND '" + endTime + "')"
	goodsWhere = " AND (g.start_time BETWEEN '" + startTime + "' AND '" + endTime + "')"
	personWhere = " AND (s.start_time BETWEEN '" + startTime + "' AND '" + endTime + "')"
	wechatWhere = " AND (w.add_time BETWEEN '" + startTime + "' AND '" + endTime + "')"

	merchantIDList, err1 := common.Order{}.GetMerchantChildren(ctx, merchantID, shopIDList)
	if err1 != nil {
		err = err1
		return
	}
	tx.Where("o.merchant_id in (?)", merchantIDList)

	salesIDList := []string{}
	if salesID != "" {
		var saleString string
		for _, v := range strings.Split(salesID, ",") {
			saleString += " \"" + v + "\","
			if !lo.Contains(salesIDList, v) {
				salesIDList = append(salesIDList, v)
			}
		}
		saleString = strings.TrimSuffix(saleString, ",")
		areaWhere += " and o2.sales_id in (" + saleString + ")"
		goodsWhere += " and g.sales_id in (" + saleString + ")"
		personWhere += " and s.sales_id in (" + saleString + ")"
		wechatWhere += " and w.sales_id in (" + saleString + ")"
		tx.Where("o.sales_id in (?)", strings.Split(salesID, ","))
	}

	if areas1 != "" {
		tx.Where("o.areas1 in (?)", strings.Split(areas1, ","))
	}

	if areas2 != "" {
		tx.Where("o.areas2 in (?)", strings.Split(areas2, ","))
	}

	if areas3 != "" {
		tx.Where("o.areas3 in (?)", strings.Split(areas3, ","))
		areasSalesList := dao.Robot{}.GetSalesIDByAreas3(ctx, db, strings.Split(areas3, ","))
		areasSalesIDList := []string{}
		if len(areasSalesList) > 0 {
			var saleString string
			for _, v := range areasSalesList {
				saleString += " \"" + v + "\","
				if !lo.Contains(areasSalesIDList, v) {
					areasSalesIDList = append(areasSalesIDList, v)
				}
			}
			saleString = strings.TrimSuffix(saleString, ",")
			areaWhere += " and o2.sales_id in (" + saleString + ")"
			goodsWhere += " and g.sales_id in (" + saleString + ")"
			personWhere += " and s.sales_id in (" + saleString + ")"
			wechatWhere += " and w.sales_id in (" + saleString + ")"
			tx.Where("o.sales_id in (?)", areasSalesList)
			if len(salesIDList) > 0 { // 机器 + 地区 => 取交集
				salesIDList = lo.Intersect(salesIDList, areasSalesList)
			} else {
				salesIDList = areasSalesList
			}
		}
	}
	var Res []HourOrderDescReturn
	field := "date_format(o.add_time, '%H') as hour, o.sales_id, o.order_status, sum(o.payment_amount) as gmv," +
		"(SELECT sum(payment_amount) FROM ma_order AS o2 WHERE order_status IN (4) AND date_format(o2.add_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + areaWhere +
		") AS my_payment_amount," +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE order_status IN (1,3,4,6) AND date_format(o2.add_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + areaWhere +
		") AS my_order_count, " +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE order_status = 6 AND date_format(o2.add_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + areaWhere +
		") AS my_refund_order_count, " +
		"(SELECT sum(payment_amount) FROM ma_order AS o2 WHERE order_status = 6 AND date_format(o2.add_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + areaWhere +
		") AS my_refund_order_amount, " +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status in(1,3,4,5,6) AND date_format(o2.add_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + areaWhere +
		") AS my_start_order_count, " +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE order_status in(4) AND date_format(o2.add_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + areaWhere +
		") AS my_success_order_count," +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status IN(1,2,3,4,5,6) AND date_format(o2.add_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + areaWhere +
		") AS my_all_order_count," +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status IN(7) AND date_format(o2.add_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + areaWhere +
		") AS my_failed_order_count," +
		"(SELECT count(order_id) FROM ma_order AS o2 WHERE o2.order_status IN(1,3) AND date_format(o2.add_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + areaWhere +
		") AS my_not_pay_order_count," +
		"(SELECT sum(g.click_num) FROM ma_goods_click AS g WHERE date_format(g.start_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + goodsWhere +
		") AS click_num," +
		"(SELECT count(DISTINCT w.unique_id) FROM ma_wechat_rate w where w.sales_id = o.sales_id AND date_format(w.add_time, '%Y-%m-%d %H') = date_format(o.add_time, '%Y-%m-%d %H') " + wechatWhere +
		") AS pay_num"

	tx.Joins("left join " + models.MaRobot{}.TableName() + " r on r.sales_id = o.sales_id").
		Group("date_format(o.add_time, '%Y-%m-%d %H')").
		Select(field).
		Find(&Res)
	var HourResMap = make(map[string]HourOrderDescReturn)
	for _, v := range Res {
		HourResMap[v.Hour] = v
	}
	robotList, _, _ := dao.Robot{}.RobotList(ctx, db, "", "", "", strings.Join(salesIDList, ","), "", "", "", "")
	var RobotNameList = []string{}
	for _, v := range robotList {
		RobotNameList = append(RobotNameList, v.RobotName)
	}
	robotNames := strings.Join(RobotNameList, ",")
	HourFaceCount := dao.FaceCount{}.GetHourFaceCount(ctx, dal.Q, merchantIDList, date, robotNames)
	HourList := []string{"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13",
		"14", "15", "16", "17", "18", "19", "20", "21", "22", "23"}
	var ResReturn = []HourOrderDescReturn{}
	for k, v := range HourList {
		var item = HourOrderDescReturn{
			Hour: v,
		}
		if _, ok := HourResMap[v]; ok {
			item = HourResMap[v]
		}
		item.Facecount = HourFaceCount.FaceCount24[k].FaceCount
		item.Facecount0 = HourFaceCount.FaceCount24[k].FaceCount0
		item.Facecount1 = HourFaceCount.FaceCount24[k].FaceCount1
		item.Facecount2 = HourFaceCount.FaceCount24[k].FaceCount2
		item.Facecount3 = HourFaceCount.FaceCount24[k].FaceCount3
		ResReturn = append(ResReturn, item)
	}
	sort.Slice(ResReturn, func(i, j int) bool {
		return ResReturn[i].Hour < ResReturn[j].Hour
	})
	return ResReturn, nil
}
